﻿using System;
using TouchTable;
using UnityEngine;
using TouchTable.Event;
using System.Collections.Generic;

namespace UnityTouchTable.Runtime
{
    /// <summary>
    /// Unity 识别桌入口
    /// </summary>
    [AddComponentMenu("TouchTable/UnityTouchTableEntry", 1)]
    [DisallowMultipleComponent]
    public class UnityTouchTableEntry : MonoBehaviour, ITouchTableEntry
    {
        #region EventHandler
        /// <summary>
        /// 当添加Mark时
        /// </summary>
        private EventHandler<MarkEventArgs> m_OnAddMarks;

        /// <summary>
        /// 当更新Mark时
        /// </summary>
        private EventHandler<MarkEventArgs> m_OnUpdateMarks;

        /// <summary>
        /// 当移除Mark时
        /// </summary>
        private EventHandler<MarkEventArgs> m_OnRemoveMarks;
        #endregion

        #region Event
        /// <summary>
        /// 当添加Mark时
        /// </summary>
        public event EventHandler<MarkEventArgs> OnAddMarks
        {
            add { this.m_OnAddMarks += value; }
            remove { this.m_OnAddMarks -= value; }
        }

        /// <summary>
        /// 当更新Mark时
        /// </summary>
        public event EventHandler<MarkEventArgs> OnUpdateMarks
        {
            add { this.m_OnUpdateMarks += value; }
            remove { this.m_OnUpdateMarks -= value; }
        }

        /// <summary>
        /// 当移除Mark时
        /// </summary>
        public event EventHandler<MarkEventArgs> OnRemoveMarks
        {
            add { this.m_OnRemoveMarks += value; }
            remove { this.m_OnRemoveMarks -= value; }
        }
        #endregion

        #region Field
        /// <summary>
        /// 许可数据
        /// </summary>
        [SerializeField]
        private string m_LicenseData = default;

        /// <summary>
        /// 处理模式
        /// </summary>
        [SerializeField]
        private ProcessMode m_ProcessMode = ProcessMode.Internal;

        /// <summary>
        /// 模拟
        /// </summary>
        [SerializeField]
        private bool m_Simulation = false;

        /// <summary>
        /// 最小移动距离
        /// </summary>
        [SerializeField]
        private float m_MinMoveDistance = 2.5f;

        /// <summary>
        /// 最小旋转角度
        /// </summary>
        [SerializeField]
        private float m_MinRotateAngle = 2.5f;

        /// <summary>
        /// 强制更新
        /// </summary>
        [SerializeField]
        private bool m_ForcedUpdate = false;

        /// <summary>
        /// 日志
        /// </summary>
        [SerializeField]
        private string m_LogHelper = "UnityTouchTable.Runtime.DefaultLogHelper";

        /// <summary>
        /// 开启日志
        /// </summary>
        [SerializeField]
        private bool m_EnableLog = true;

        /// <summary>
        /// 触摸输入
        /// </summary>
        [SerializeField]
        private string m_InputHelper = "UnityTouchTable.Runtime.TouchInput";

        /// <summary>
        /// 识别桌管理器接口
        /// </summary>
        private ITouchTableManager m_ITouchTableManager;

        /// <summary>
        /// Marker项
        /// 处理Unity无法序列化字典的折中做法
        /// </summary>
        [SerializeField]
        private MarkerItemBase[] m_Marks = null;

        /// <summary>
        /// Marker项
        /// </summary>
        private Dictionary<int, IMarkerItem> m_MarkerItems = new Dictionary<int, IMarkerItem>();
        #endregion

        private void Start()
        {
            if (string.IsNullOrEmpty(this.m_LicenseData))
            {
                Debug.LogError("license data is invalid...");
                return;
            }

            this.m_ITouchTableManager = TouchTableEntry.GetEntry();
            this.m_ITouchTableManager.SetITouchTableEntry(this);

            this.m_ITouchTableManager.Init
            (
                this.m_LicenseData,
                this.m_Simulation, Screen.width, Screen.height,
                this.m_MinMoveDistance, this.m_MinRotateAngle,
                this.m_ForcedUpdate, Screen.dpi, Type.GetType(this.m_LogHelper),
                this.m_EnableLog, Type.GetType(this.m_InputHelper)
            );

            //添加标记项
            this.m_MarkerItems.Clear();
            for (int i = 0; i < this.m_Marks.Length; i++)
            {
                MarkerItemBase markerItemBase = this.m_Marks[i];
                if (this.m_MarkerItems.ContainsKey(markerItemBase.MarkerItemID))
                {
                    Debug.LogWarning($"add mark id {markerItemBase.MarkerItemID} failure...");
                    continue;
                }
                else
                {
                    this.m_MarkerItems.Add(markerItemBase.MarkerItemID, markerItemBase);
                    markerItemBase.Init();
                }
            }
        }

        private void Update()
        {
            this.m_ITouchTableManager?.Update();
        }

        private void OnDestroy()
        {
            this.m_ITouchTableManager?.Break();
        }

        #region Function
        /// <summary>
        /// 新增Mark
        /// </summary>
        /// <param name="markEventArgs">新增事件参数</param>
        public void AddMarks(MarkEventArgs markEventArgs)
        {
            switch (this.m_ProcessMode)
            {
                case ProcessMode.Internal:
                    {
                        List<Marker> markers = markEventArgs.Markers;
                        for (int i = 0; i < markers.Count; i++)
                        {
                            Marker marker = markers[i];
                            if (!this.m_MarkerItems.ContainsKey(marker.ID))
                                continue;

                            this.m_MarkerItems[marker.ID].AddMarker(new Vector2(marker.CenterPosition.X, marker.CenterPosition.Y), marker.InitAngle);
                        }
                    }
                    break;
                case ProcessMode.Custom:
                    this.m_OnAddMarks?.Invoke(this, markEventArgs);
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 更新Mark
        /// </summary>
        /// <param name="markEventArgs">更新事件参数</param>
        public void UpdateMarks(MarkEventArgs markEventArgs)
        {
            switch (this.m_ProcessMode)
            {
                case ProcessMode.Internal:
                    {
                        List<Marker> markers = markEventArgs.Markers;
                        for (int i = 0; i < markers.Count; i++)
                        {
                            Marker marker = markers[i];
                            if (!this.m_MarkerItems.ContainsKey(marker.ID))
                                continue;

                            this.m_MarkerItems[marker.ID].UpdateMarker(new Vector2(marker.CenterPosition.X, marker.CenterPosition.Y), marker.InitAngle, marker.CurrentAngle, marker.RelativeAngle);
                        }
                    }
                    break;
                case ProcessMode.Custom:
                    this.m_OnUpdateMarks?.Invoke(this, markEventArgs);
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 移除Mark
        /// </summary>
        /// <param name="markEventArgs">移除事件参数</param>
        public void RemoveMarks(MarkEventArgs markEventArgs)
        {
            switch (this.m_ProcessMode)
            {
                case ProcessMode.Internal:
                    {
                        List<Marker> markers = markEventArgs.Markers;
                        for (int i = 0; i < markers.Count; i++)
                        {
                            Marker marker = markers[i];
                            if (!this.m_MarkerItems.ContainsKey(marker.ID))
                                continue;

                            this.m_MarkerItems[marker.ID].RemoveMarker();
                        }
                    }
                    break;
                case ProcessMode.Custom:
                    this.m_OnRemoveMarks?.Invoke(this, markEventArgs);
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 添加IMarkerItem
        /// </summary>
        /// <param name="markerItem">待添加的IMarkerItem</param>
        internal void AddMarkerItem(IMarkerItem markerItem)
        {
            if (this.m_MarkerItems.ContainsKey(markerItem.MarkerItemID))
                return;

            this.m_MarkerItems.Add(markerItem.MarkerItemID, markerItem);
            markerItem.Init();
        }

        /// <summary>
        /// 移除IMarkerItem
        /// </summary>
        /// <param name="markerItemID">待移除的IMarkerItem</param>
        internal void RemoveMarkerItem(int markerItemID)
        {
            if (!this.m_MarkerItems.ContainsKey(markerItemID))
                return;

            this.m_MarkerItems.Remove(markerItemID);
        }
        #endregion
    }
}